package com.kylin.core.commodity.query.handler;

import com.kylin.dal.entity.commodity.*;
import com.kylin.dal.entity.marketing.QMarketingBoardEntry;
import com.kylin.dal.entity.marketing.QMarketingCampaignEntry;
import com.kylin.domain.authority.command.*;
import com.kylin.domain.commodity.vo.CommodityVO;
import com.kylin.shared.common.PageResults;
import com.kylin.shared.common.consts.Constants;
import com.kylin.shared.enums.*;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 商品查询处理类(查)
 * @author Damon S.
 * @version v1.0.1
 * @date 2019年11月10日 14:55
 */
@Slf4j
@Component
public class CommodityQueryHandler {

    private final JPAQueryFactory commodityQueryFactory;
    private final QCommodityEntry qCommodityEntry;
    private final QCommentEntry qCommentEntry;
    private final QCommodityAlbumEntry qCommodityAlbumEntry;
    private final QCommodityHtmlEntry qCommodityHtmlEntry;
    private final QMarketingCampaignEntry qMarketingCampaignEntry;
    private final QMarketingBoardEntry qMarketingBoardEntry;
    private final CommodityTranslator commodityTranslator;

    public CommodityQueryHandler(@Qualifier("kylinArtworkEntityManager")EntityManager entityManager,
                                 CommodityTranslator commodityTranslator) {
        this.commodityQueryFactory = new JPAQueryFactory(entityManager);
        this.qCommodityEntry = QCommodityEntry.commodityEntry;
        this.qCommentEntry = QCommentEntry.commentEntry;
        this.qMarketingCampaignEntry = QMarketingCampaignEntry.marketingCampaignEntry;
        this.qMarketingBoardEntry = QMarketingBoardEntry.marketingBoardEntry;
        this.qCommodityHtmlEntry = QCommodityHtmlEntry.commodityHtmlEntry;
        this.qCommodityAlbumEntry = QCommodityAlbumEntry.commodityAlbumEntry;
        this.commodityTranslator = commodityTranslator;
    }

    @QueryHandler
    public PageResults findCommentsByCommodityId(QueryCommentCommand command) {
        QueryResults<CommentEntry> entries = commodityQueryFactory.selectFrom(qCommentEntry)
                        .where(qCommentEntry.commodityId.eq(command.getCommodityId())
                                .and(qCommentEntry.removed.eq(YesNoEnum.N.getCode())))
                        .orderBy(qCommentEntry.createdAt.desc())
                        .offset((command.getPageIndex() - Constants.LONG_ONE) * command.getPageSize())
                        .limit(command.getPageSize())
                        .fetchResults();
        // 返回查询结果
        return PageResults.builder()
                .index(command.getPageIndex())
                .limit(command.getPageSize())
                .total(entries.getTotal())
                .results(this.commodityTranslator.toCommentVO(entries.getResults()))
                .build();
    }

    @QueryHandler
    private PageResults findCommoditiesByPage(QueryCommodityCommand command) {
        Long currentSeconds = LocalDateTime.now().toEpochSecond(
                        OffsetDateTime.now().getOffset()
                );
        // 各种过滤条件
        BooleanExpression expression = qCommodityEntry.state.eq(ApprovalState.APPROVED.getCode())
                .and(qCommodityEntry.shelved.eq(YesNoEnum.Y.getCode()))
                .and(qCommodityEntry.removed.eq(YesNoEnum.N.getCode()))
                .and(qMarketingCampaignEntry.startAt.lt(currentSeconds))
                .and(qMarketingCampaignEntry.stopAt.gt(currentSeconds))
                .and(qMarketingCampaignEntry.campaignState.eq(CampaignState.PUBLISHED.getCode()))
                .and(qMarketingBoardEntry.state.eq(RunningState.RUNNING.getCode()));
        Optional.ofNullable(command.getCommodityCode()).ifPresent(
                code -> expression.and(qCommodityEntry.code.eq(code))
        );
        if (!MarketingType.NA.equals(command.getMarketingType())) {
            expression.and(qMarketingCampaignEntry.type.eq(command.getMarketingType().getCode()));
        }
        // 构建查询语句
        QueryResults<CommodityEntry> entries =
                this.commodityQueryFactory.selectFrom(qCommodityEntry)
                        .leftJoin(qMarketingBoardEntry)
                        .on(qMarketingBoardEntry.commodityId.eq(qCommodityEntry.commodityId))
                        .leftJoin(qMarketingCampaignEntry)
                        .on(qMarketingCampaignEntry.campaignId.eq(qMarketingBoardEntry.campaignId))
                        .where(expression)
                        .orderBy(qMarketingCampaignEntry.sort.desc(), qMarketingBoardEntry.sort.desc())
                        .offset((command.getPageIndex() - Constants.LONG_ONE) * command.getPageSize())
                        .limit(command.getPageSize())
                        .fetchResults();
        // 返回查询结果
        return PageResults.builder()
                .index(command.getPageIndex())
                .limit(command.getPageSize())
                .total(entries.getTotal())
                .results(this.commodityTranslator.toCommodityVO(entries.getResults()))
                .build();
    }

    @QueryHandler
    public List<CommodityVO> findCommoditiesByIds(QueryCommoditiesByIdsCommand command) {
        return commodityTranslator.toCommodityVO(
                commodityQueryFactory.selectFrom(qCommodityEntry)
                        .where(qCommodityEntry.commodityId.in(command.getCommodityIds())
                                .and(qCommodityEntry.removed.eq(YesNoEnum.N.getCode()))
                        ).fetch()
        );
    }

    @QueryHandler
    public CommodityVO findCommodityByCommodityId(QueryCommodityByIdCommand command) {
        CommodityEntry entry = commodityQueryFactory.selectFrom(qCommodityEntry)
                .where(qCommodityEntry.commodityId.eq(command.getCommodityId())
                        .and(qCommodityEntry.removed.eq(YesNoEnum.N.getCode()))
                ).fetchOne();
        if (Objects.isNull(entry)) {
            return CommodityVO.EMPTY;
        }
        CommodityVO commodityVO = this.commodityTranslator.toCommodityVO(entry);
        // 查询图片
        List<CommodityAlbumEntry> entries = commodityQueryFactory.selectFrom(qCommodityAlbumEntry)
                .where(qCommodityAlbumEntry.commodityId.eq(command.getCommodityId())
                        .and(qCommodityAlbumEntry.removed.eq(YesNoEnum.N.getCode()))
                ).orderBy(qCommodityAlbumEntry.sort.desc())
                .fetch();
        if (!CollectionUtils.isEmpty(entries)) {
            commodityVO.setAlbums(
                    commodityTranslator.toAlbumVO(entries)
            );
        }
        return commodityVO;
    }

    @QueryHandler
    private String findCommodityDescById(QueryHtmlByCommodityIdCommand command) {
        CommodityHtmlEntry entry = commodityQueryFactory.selectFrom(qCommodityHtmlEntry)
                .where(qCommodityHtmlEntry.commodityId.eq(command.getCommodityId()))
                .fetchOne();
        return Objects.isNull(entry) ? Constants.STR_EMPTY : entry.getDescription();
    }
}
